function h5attput(h5file,varname,attname,attvalue)
%H5ATTPUT  Write HDF5 attribute.
%
%   H5ATTPUT(H5FILE,VARNAME,ATTNAME,ATTVALUE) creates/overwrites the 
%   attribute named ATTNAME with the value ATTVALUE.  The parent object 
%   VARNAME can be either an HDF5 variable or group.  VARNAME must be a 
%   complete pathname.
%
%   Simple strings will be created in a scalar dataspace.
%
%   If H5FILE does not exist, it will be created.  In this case, the parent 
%   object must be '/' , (the root group)
%
%   See also h5attget.

%   Copyright 2008-2010 The MathWorks, Inc.


if ~ischar(varname)
	error('MATLAB:H5ATTPUT:badDatatype', ...
	      'VARNAME input argument must have datatype char.' );
end

if ~ischar(attname)
	error('MATLAB:H5ATTPUT:badDatatype', ...
	      'ATTNAME input argument must have datatype char.' );
end

flags = 'H5F_ACC_RDWR';
plist_id = 'H5P_DEFAULT';

% Allow for the user to pass the file ID directly.
if ischar(h5file)
    if ~exist(h5file,'file')
        create_plist = H5P.create('H5P_FILE_CREATE');
        file_id = H5F.create(h5file,'H5F_ACC_TRUNC', create_plist, 'H5P_DEFAULT');
        H5P.close(create_plist);
    else
        file_id = H5F.open ( h5file, flags, plist_id );
    end
else
    file_id = h5file;
end


parent_id     = set_attribute_parent_id(file_id,varname);
dataspace_id  = set_dataspace_id(attvalue);
datatype_id   = set_datatype_id(attvalue);
att_id        = set_attribute_id(parent_id,attname,datatype_id,dataspace_id);
write_att(att_id,datatype_id,attvalue);

% Close all the IDs.
H5T.close(datatype_id);
H5S.close(dataspace_id);
H5A.close(att_id);

close_attribute_parent_id(file_id,varname,parent_id);

if ischar(h5file)
    H5F.close(file_id);
end




%--------------------------------------------------------------------------
function write_att(att_id,datatype_id,attvalue)
% We have to be careful about complex values.
switch(class(attvalue))
    case {'double','single'}
        if isreal(attvalue)
            H5A.write(att_id,datatype_id,attvalue);
        else
            cvalue.real = real(attvalue);
            cvalue.imag = imag(attvalue);
            H5A.write(att_id,datatype_id,cvalue);
        end
    otherwise
        H5A.write(att_id,datatype_id,attvalue);
end
            
%--------------------------------------------------------------------------
function att_id = set_attribute_id(parent_id,attname,datatype_id,dataspace_id)
% Setup the attribute ID.  We need to check as to whether or not the attribute
% already exists.

try
	att_id = H5A.open_name ( parent_id, attname );
catch %#ok<CTCH>
	att_id = H5A.create ( parent_id, attname, datatype_id, dataspace_id,'H5P_DEFAULT' );
end

%--------------------------------------------------------------------------
function dataspace_id = set_dataspace_id ( attvalue )
% Setup the dataspace ID.  This just depends on how many elements the 
% attribute actually has.

if ischar(attvalue)
    if ( ndims(attvalue) == 2 ) && ( any(size(attvalue) ==1) )
        dataspace_id = H5S.create('H5S_SCALAR');
        return
    elseif ndims(attvalue < 3)
        rank = 1;
        dims = size(attvalue,2);
    else
        error('HDF5TOOLS:h5attput:badStringSize', ...
            'Cannot accept a string input with ndims > 2.');
    end
else
    if ( ndims(attvalue) == 2 ) && ( any(size(attvalue) ==1) )
        rank = 1;
        dims = numel(attvalue);
    else
        % attribute is a "real" 2D value.		
        rank = ndims(attvalue);
	    dims = fliplr(size(attvalue));
    end
end
dataspace_id = H5S.create_simple ( rank, dims, dims );








%--------------------------------------------------------------------------
function datatype_id = set_datatype_id ( attvalue )
% We need to choose an appropriate HDF5 datatype based upon the attribute
% data.
switch class(attvalue)
    case 'double'
        if isreal(attvalue)
            datatype_id = H5T.copy('H5T_NATIVE_DOUBLE');
        else
            % complex
            datatype_id = H5T.create('H5T_COMPOUND',16);
            H5T.insert(datatype_id,'real',0,'H5T_NATIVE_DOUBLE');
            H5T.insert(datatype_id,'imag',8,'H5T_NATIVE_DOUBLE');
        end
    case 'single'
        if isreal(attvalue)
            datatype_id = H5T.copy('H5T_NATIVE_FLOAT');
        else
            % complex
            datatype_id = H5T.create('H5T_COMPOUND',8);
            H5T.insert(datatype_id,'real',0,'H5T_NATIVE_FLOAT');
            H5T.insert(datatype_id,'imag',4,'H5T_NATIVE_FLOAT');
        end
    case 'int64'
        datatype_id = H5T.copy('H5T_NATIVE_LLONG');
    case 'uint64'
        datatype_id = H5T.copy('H5T_NATIVE_ULLONG');
    case 'int32'
        datatype_id = H5T.copy('H5T_NATIVE_INT');
    case 'uint32'
        datatype_id = H5T.copy('H5T_NATIVE_UINT');
    case 'int16'
        datatype_id = H5T.copy('H5T_NATIVE_SHORT');
    case 'uint16'
        datatype_id = H5T.copy('H5T_NATIVE_USHORT');
    case 'int8'
        datatype_id = H5T.copy('H5T_NATIVE_SCHAR');
    case 'uint8'
        datatype_id = H5T.copy('H5T_NATIVE_UCHAR');
    case 'char'
        datatype_id = H5T.copy('H5T_C_S1');
        if any(size(attvalue) == 1)
            H5T.set_size(datatype_id,numel(attvalue));
        else
            H5T.set_size(datatype_id,size(attvalue,1));
        end
		H5T.set_strpad(datatype_id,'H5T_STR_NULLTERM');
	otherwise 
		error('MATLAB:H5ATTPUT:unsupportedDatatype', ...
		       '''%s'' is not a supported H5ATTPUT datatype.\n', class(attvalue) );
end
return

